<?PHP

/*
Plugin Name: OnePress Akismet for Accounts
Plugin URI: http://onepresscommunity.com/akismet-for-accounts/
Description: Check for spammers when users register and login to your WordPress site.  Uses the Akismet API to verify that user is not a spammer.
Version: 1.0
Author: Sean Sullivan
Author URI: http://onepresscommunity.com
*/

$op_user_akismet_options = null;

class OP_AkismetAccounts{
	function init(){
		add_action('register_post', array('OP_AkismetAccounts','register'),10,2);
		add_filter('authenticate', array('OP_AkismetAccounts','login'), 10,2);
		
		add_action('admin_menu', array('OP_AkismetAccounts','admin'));
		
		global $op_user_akismet_options;
		if(!$op_user_akismet_options = get_option('op_user_akismet')){
			add_option('op_user_akismet',array());
			$op_user_akismet_options = array();
		}
	}
	
	function admin(){
		if ( function_exists('add_submenu_page') ){
			add_submenu_page('users.php', __('Mark Spammers &amp; Hammers'), __('Mark Spammers &amp; Hammers'), 'manage_options', __FILE__, array('OP_AkismetAccounts','user_admin_display'));
			add_submenu_page('plugins.php', __('OnePress Akismet for Accounts'), __('OnePress Akismet for Accounts'), 'manage_options', __FILE__, array('OP_AkismetAccounts','user_admin_menu'));
		}
	}
	
	function user_admin_menu(){
		if ( !current_user_can('manage_options') )
			die;
			
		global $op_user_akismet_options;
		
		if ( isset($_REQUEST['docheck']) ){
			check_admin_referer('op-users-akismet');
			$op_user_akismet_options = array_diff($_REQUEST['docheck'],$op_user_akismet_options);
			update_option('op_user_akismet',$op_user_akismet_options);
		}
		
		echo '<div class="wrap">',
			'<h2>OnePress Akismet for Users</h2>',
			'<div class="narrow">',
			'<form method="post" action="">';
			wp_nonce_field('op-users-akismet');
		
		echo '<p><label>WordPress API Key:</label><br/>';
		
		if(!$api_key = get_option('wordpress_api_key')){
			add_option('wordpress_api_key','');
			echo '<p>Please provide a WordPress API key in order to use this plug-in.</p>';
		}
		else if(!OP_AkismetAccounts::verify_key()){
			echo '<p>Your WordPress API key is not valid, please enter the correct key and resubmit</p>';
		}
		
		if( isset($_REQUEST['api_key']) ){
			$api_key = stripslashes(trim($_REQUEST['api_key']));
			update_option('wordpress_api_key',$api_key);
		}
		
		echo '<input type="text" name="api_key" value="'.$api_key.'">';

		echo '</p><p>',
			'<label>Use Akismet check for users when:</label><br/>',
			'<p><input type="checkbox" name="docheck[]" value="register"',
			(in_array('register',$op_user_akismet_options) ? ' CHECKED' : ''),
			'/> Registering<br/>',
			'<input type="checkbox" name="docheck[]" value="login"',
			(in_array('login',$op_user_akismet_options) ? ' CHECKED' : ''),
			'/> Logging In<br/></p>',
			'<p class="submit"><input type="submit" value="Update Settings"/></p>',
			'</p>',
			'</form>',
			'<p>For more information about this plug-in, visit <a href="http://onepresscommunity.com">OnePress Community</a>.  Ask any questions you may have on the <a href="http://onepresscommunity.com/forum/">OnePress Community forums</a>.',
			'</div></div>';
	}
	
	function user_admin_display(){
		if ( !current_user_can('edit_users') )
			die;

		if ( isset($_REQUEST['action']) )
			$doaction = $_REQUEST['action'] ? $_REQUEST['action'] : $_REQUEST['action2'];
		
		echo '<div class="wrap">';
		screen_icon();
		echo '<h2>'.wp_specialchars( 'Mark Spammers &amp; Hammers' ).'</h2>';
		echo "<p>Users on this page can be marked as hammers or spammers.  Doing so notifies the Akismet service of your marking of the user.  Only users who have an IP on record will be displayed here for marking. Simply select the checkbox next to the user(s) name and choose the type you wish to mark them as from the drop down menu and click apply.</p>";
		echo '<form id="posts-filter" action="" method="post">';
		
		if ( empty($_REQUEST) ) {
			$referer = '<input type="hidden" name="wp_http_referer" value="'. attribute_escape(stripslashes($_SERVER['REQUEST_URI'])) . '" />';
		} elseif ( isset($_REQUEST['wp_http_referer']) ) {
			$redirect = remove_query_arg(array('wp_http_referer', 'updated', 'delete_count'), stripslashes($_REQUEST['wp_http_referer']));
			$referer = '<input type="hidden" name="wp_http_referer" value="' . attribute_escape($redirect) . '" />';
		} else {
			$redirect = 'users.php';
			$referer = '';
		}
		
		if(in_array($doaction,array('hammer','spammer'))){
			check_admin_referer('bulk-users');
		
			if (empty($_REQUEST['users'])) {
				wp_redirect($redirect);
				exit();
			}

			$userids = $_REQUEST['users'];
			$update = 'promote';
			foreach($userids as $id) {
				OP_AkismetAccounts::submit_user($id,$doaction);
			}
			echo '<p>Users have been marked as '.$doaction.'</p>';
		}
		$userspage = isset($_GET['userspage']) ? $_GET['userspage'] : null;
		$userspage = (int) ( '' == $userspage ) ? 1 : $userspage;
		
		echo '<div class="tablenav">';
		
		global $wpdb;
		
		$users_with_ip = $wpdb->get_results("SELECT u.ID FROM $wpdb->users u RIGHT JOIN $wpdb->usermeta um ON u.ID=um.user_id WHERE um.meta_key='user_ip' ORDER BY u.user_registered DESC",ARRAY_A);

		$users_per_page = 50;
		$total_users_for_query = count($users_with_ip);
		
		$users_with_ip = $total_users_for_query > 0 ? array_slice($users_with_ip,($userspage*$users_per_page)-$users_per_page,$users_per_page) : array();
		
		if ( $total_users_for_query > $users_per_page ){
			$page_links = paginate_links( array(
				'total' => ceil($total_users_for_query / $users_per_page),
				'current' => $userspage,
				'base' => 'users.php?%_%',
				'format' => 'userspage=%#%'
			) );
			preg_match('/\/(\w+)$/i',dirname(__FILE__),$path_match);
			$path = $path_match[1].'/'.basename(__FILE__);
			
			$page_links = preg_replace_callback('/(\?(userspage\=[0-9]+)?)/',
				create_function('$match','return strlen($match[2]) > 0 ? "?page='.$path.'&".$match[2] : "?page=op_bozos/bozos.php";'),
				$page_links
			);
			
			if ( $page_links ) {
				$page_links = sprintf( '<span class="displaying-num">' . __( 'Displaying %s&#8211;%s of %s' ) . '</span>%s',
					number_format_i18n( ( $userspage - 1 ) * $users_per_page + 1 ),
					number_format_i18n( min( $userspage * $users_per_page, $total_users_for_query ) ),
					number_format_i18n( $total_users_for_query ),
					$page_links
				);
			}
			echo '<div class="tablenav-pages">'.$page_links.'</div>';
		}
		
		echo '</div>';
		
		wp_nonce_field('bulk-users');
		
		echo '<div class="alignleft actions">',
			'<select name="action">',
			'<option value="" selected="selected">';
		_e('Mark Users');
		echo '</option>',
			'<option value="spammer">';
		_e('Spammer');
		echo '</option>',
			'<option value="hammer">';
		_e('Hammer');
		echo '</option>',
			'</select>',
			'<input type="submit" value="';
		_e('Apply');
		echo '" name="doaction" id="doaction" class="button-secondary action" />',
			'</div>';
		
		echo '<table class="widefat fixed" cellspacing="0">',
			'<thead>',
			'<tr class="thead">';
			
		print_column_headers('users');
		
		echo '</tr>',
			'</thead>',
			'<tfoot>',
			'<tr class="thead">',
		
		print_column_headers('users', false);
		
		echo '</tr>',
			'</tfoot>',
			'<tbody id="users" class="list:user user-list">';

		$style = '';

		foreach($users_with_ip as $userid){
			$user_object = new WP_User($userid['ID']);
			$roles = $user_object->roles;
			$role = array_shift($roles);
		
			$style = ( ' class="alternate"' == $style ) ? '' : ' class="alternate"';
			$user_row = user_row($user_object, $style, $role);
			echo "\n\t" . user_row($user_object, $style, $role);
		}
		
		echo '</tbody>',
			'</table>';
			
		echo '<div class="alignleft actions">',
			'<select name="action2">',
			'<option value="" selected="selected">';
		_e('Mark Users');
		echo '</option>',
			'<option value="spammer">';
		_e('Spammer');
		echo '</option>',
			'<option value="hammer">';
		_e('Hammer');
		echo '</option>',
			'</select>',
			'<input type="submit" value="';
		_e('Apply');
		echo '" name="doaction" id="doaction2" class="button-secondary action" />',
			'</div>';
			
		echo '</div>';
	}
	
	function login($null,$username){
		global $op_user_akismet_options;
		
		$user = get_userdatabylogin($username);
		update_usermeta($user->ID,'user_ip',$_SERVER['REMOTE_ADDR']); // when user logs in, update ip in metadata
		
		if(!in_array('login',$op_user_akismet_options)) return;
		
		global $errors;

		$data = array(
			'comment_author'		=> $username,
			'comment_author_email'	=> $user->email,
			'comment_type'			=> 'login'
		);
		
		OP_AkismetAccounts::submit($data);
		return $errors;
	}
	
	function register($username,$email){
		global $op_user_akismet_options;
		
		if(!in_array('register',$op_user_akismet_options)) return;
		
		$data = array(
			'comment_author'		=> $username,
			'comment_author_email'	=> $email,
			'comment_type'			=> 'registration'
		);
		
		OP_AkismetAccounts::submit($data);
	}
	
	function submit_user($user_id,$type='hammer'){
		$user = get_userdata($user_id);
		if(!$ip = get_usermeta($id,'user_ip')) return;
		
		$data = array(
			'comment_author'		=> $user->user_login,
			'comment_author_email'	=> $user->user_email,
			'comment_type'			=> 'admin_define_user',
			'user_ip'				=> $ip
		);

		$type = substr($type,0,-3); // hammer becomes ham, spammer becomes spam

		OP_AkismetAccounts::submit($data,$type);
	}

	function verify_key(){
		$api_key = get_option('wordpress_api_key');
		$response = OP_AkismetAccounts::submit(array('key'=>$api_key), 'verify-key');
		
		if ( 'valid' == $response[1] )
			return true;
		else
			return false;	
	}
		
	function submit($request_args=array(),$type='comment-check'){
		
		$api_key = get_option('wordpress_api_key');
		$akismet_api_host = $api_key . '.rest.akismet.com';
		$akismet_api_port = 80;
		
		$data = array(
			'blog' => get_option('siteurl'),
		);
		
		$request_args = array_merge($data,$request_args);
		

		// verify-key method doesn't use API key as subdomain
		if($type == 'verify-key'){
			$akismet_api_host = 'rest.akismet.com';
		}
		else{ // other methods use user_ip and user_agent
			if($type != 'comment-check'){
				$type = 'submit-'.$type; // ham and spam
			}
			
			$request_args = array_merge($request_args,array(
				'user_ip' => preg_replace( '/[^0-9., ]/', '', $_SERVER['REMOTE_ADDR'] ),
				'user_agent' => $_SERVER['HTTP_USER_AGENT']
			));
		}

		array_walk($request_args, create_function('&$value,$key','$value = $key."=".urlencode(stripslashes($value));'));
		$request_args = implode('&',$request_args);
		
		$response = OP_AkismetAccounts::op_akismet_http_post($request_args, $akismet_api_host, '/1.1/'.$type, $akismet_api_port);

		if($response[1] == 'true'){
			global $errors;	
			if(!$errors instanceof WP_Error) $errors = new WP_Error(); // check to make sure error is instance of WP_Error
			$errors->add('bozos',_('You are a bozo'));		
		}
		
		return $response;
		
	}
	
	// Returns array with headers in $response[0] and entity in $response[1]
	function op_akismet_http_post($request, $host, $path, $port = 80) {
		global $wp_version;
		$user_agent = "WordPress/$wp_version | Akismet/1.11";
	
		$http_request  = "POST $path HTTP/1.0\r\n";
		$http_request .= "Host: $host\r\n";
		$http_request .= "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n"; // for now
		$http_request .= "Content-Length: " . strlen($request) . "\r\n";
		$http_request .= "User-Agent: $user_agent\r\n";
		$http_request .= "\r\n";
		$http_request .= $request;

		$response = '';
		if( false != ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
			fwrite($fs, $http_request);
	
			while ( !feof($fs) )
				$response .= fgets($fs, 1160); // One TCP-IP packet
			fclose($fs);
			$response = explode("\r\n\r\n", $response, 2);
		}
		return $response;
	}
}

add_action('init', array('OP_AkismetAccounts','init'));

?>